/* EasyWay Game Engine
 * Copyright (C) 2006 Daniele Paggi.
 *  
 * Written by: 2006 Daniele Paggi<dshnt@hotmail.com>
 *   
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.easyway.objects.sprites2D;

import org.easyway.annotations.editor.Angle;
import org.easyway.annotations.editor.Creator;
import org.easyway.annotations.editor.Height;
import org.easyway.annotations.editor.Info;
import org.easyway.annotations.editor.Method;
import org.easyway.annotations.editor.UEditor;
import org.easyway.annotations.editor.Width;
import org.easyway.annotations.editor.X;
import org.easyway.annotations.editor.Y;
import org.easyway.interfaces.base.ITexture;
import org.easyway.objects.Camera;
import org.easyway.objects.extra.StaticObject;
import org.easyway.system.StaticRef;
import org.easyway.system.state.OpenGLState;
import org.easyway.utils.Utility;
import org.lwjgl.opengl.GL11;

/**
 * A Sprite is an Object that can moved and drown.<br>
 * It can have a Texture2 applied on or an Animation.<br>
 * It can't have any collisions: for this you must use SimpleSpriteColl class or
 * SpriteClass.<br>
 * It can be saturated, or some other effects.<br>
 * 
 * @see SpriteColl
 * @see SimpleSprite
 * @see SimpleSpriteColl
 * @author Daniele Paggi
 * 
 */
@UEditor//
public class Sprite extends SimpleSprite {

	private static final long serialVersionUID = -5617254063364952192L;

	// -----------------------------------------------------------------
	// --------------------VARIABLES------------------------------------
	// -----------------------------------------------------------------

	/**
	 * dynamic image <br>
	 * if not enabled, the image is fastest draws on screen <br>
	 * but you can't resize the image.<br>
	 * {From the last game engine changes I haven't tested this function yet}
	 */
	private boolean isStatic = false; // ?

	/** static object to draw on screen */
	private StaticObject staticObj = null; // I think that will not more use
	// TODO: comment
	/** animo of sprite */
	// public Animo animo;
	/** current image of sprite */
	// protected Texture2 image;
	/** indicates if at change image the dimensions are updated */
	public boolean autoReSizeDimensions = false;

	/** colors used to create the saturation */
	protected float colorRed = 1, colorGreen = 1, colorBlue = 1,
			colorAlpha = 1;

	/** the rotation of sprite */
	public float anglex, angley, anglez;

	/** coordinates of object in the game world */
	public float z;

	/** coordiates of drawing relative of image */
	protected int cx = 0, cy = 0;

	// -----------------------------------------------------------------
	// ---------------------CONSTRUCTORS--------------------------------
	// -----------------------------------------------------------------
	/** create a new instance of sprite */
	public Sprite() {
		this(0, 0, 0, null, 0, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(int layer) {
		this(0, 0, 0, null, layer, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * 
	 */

	public Sprite(float x, float y) {
		this(x, y, 0, null, 0, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordiante
	 */

	public Sprite(float x, float y, float z) {
		this(x, y, z, null, 0, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 */
	@Creator("x, y, image")//
	public Sprite(@X @Info("x") float x, @Y @Info("y") float y, ITexture img) {
		this(x, y, 0, img, 0, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(float x, float y, int layer) {
		this(x, y, 0, null, layer, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */
	@Creator("x, y, img, layer")//
	public Sprite(@X @Info("x") float x, @Y @Info("y") float y, ITexture img,
			@Info("layer") int layer) {
		this(x, y, 0, img, layer, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param img
	 *            the image of sprite
	 */

	public Sprite(ITexture img) {
		this(0, 0, 0, img, 0, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(ITexture img, int layer) {
		this(0, 0, 0, img, layer, false);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(float x, float y, float z, ITexture img, int layer) {
		this(x, y, z, img, layer, false);
	}

	// ---

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(boolean autoAdd, int layer) {
		this(autoAdd, 0, 0, 0, null, layer, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param layer
	 *            the depth of sprite
	 * @param idLayer
	 *            the id of Drawing-layer (drawing sheet)
	 */

	public Sprite(boolean autoAdd, int layer, int idLayer) {
		this(autoAdd, 0, 0, 0, null, layer, idLayer);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 */

	public Sprite(boolean autoAdd, float x, float y) {
		this(autoAdd, x, y, 0, null, 0, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordiante
	 */

	public Sprite(boolean autoAdd, float x, float y, float z) {
		this(autoAdd, x, y, z, null, 0, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 */

	public Sprite(boolean autoAdd, float x, float y, ITexture img) {
		this(autoAdd, x, y, 0, img, 0, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(boolean autoAdd, float x, float y, int layer) {
		this(autoAdd, x, y, 0, null, layer, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(boolean autoAdd, float x, float y, ITexture img, int layer) {
		this(autoAdd, x, y, 0, img, layer, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param img
	 *            the image of sprite
	 */

	public Sprite(boolean autoAdd, ITexture img) {
		this(autoAdd, 0, 0, 0, img, 0, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(boolean autoAdd, ITexture img, int layer) {
		this(autoAdd, 0, 0, 0, img, layer, 3);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 */

	public Sprite(boolean autoAdd, float x, float y, float z, ITexture img,
			int layer) {
		this(autoAdd, x, y, z, img, layer, 3);
	}

	// --
	/**
	 * create a new instance of sprite
	 * 
	 * @param autoAdd
	 *            if it's 'true' the object will be aut-added to the game
	 *            engine's lists.
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 * @param idLayer
	 *            the id of Drawing-layer (drawing sheet)
	 */
	public Sprite(boolean autoAdd, float x, float y, float z, ITexture img,
			int layer, int idLayer) {
		super(autoAdd, x, y, idLayer);
		this.z = z;
		setLayer(layer);
		this.image = img;
		// XXX:
		// privateCollisionList = new SingleCollisionList(this);
		if (image != null)
			setSize(image.getWidth(), image.getHeight());
		type.set("$_SPRITE");
	}

	// quads
	/**
	 * create a new instance of sprite
	 * 
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(boolean quad) {
		this(0, 0, 0, null, 0, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param layer
	 *            the depth of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(int layer, boolean quad) {
		this(0, 0, 0, null, layer, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(float x, float y, boolean quad) {
		this(x, y, 0, null, 0, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordinate
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(float x, float y, float z, boolean quad) {
		this(x, y, z, null, 0, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(float x, float y, ITexture img, boolean quad) {
		this(x, y, 0, img, 0, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param layer
	 *            the depth of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(float x, float y, int layer, boolean quad) {
		this(x, y, 0, null, layer, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	@Creator("x, y, layer, quad")//
	public Sprite(@X @Info("x") float x, @Y @Info("y") float y, ITexture img,
			@Info("layer") int layer, @Info("use quad") boolean quad) {
		this(x, y, 0, img, layer, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param img
	 *            the image of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(ITexture img, boolean quad) {
		this(0, 0, 0, img, 0, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(ITexture img, int layer, boolean quad) {
		this(0, 0, 0, img, layer, quad);
	}

	/**
	 * create a new instance of sprite
	 * 
	 * @param x
	 *            x cartesian coordinate
	 * @param y
	 *            y cartesian coordiante
	 * @param z
	 *            z cartesian coordinate
	 * @param img
	 *            the image of sprite
	 * @param layer
	 *            the depth of sprite
	 * @param quad
	 *            if the 'quad' is 'true' the object will be use the
	 *            quad-manager.<br>
	 *            Usually the quad-manager is disallowed<br>
	 */
	public Sprite(float x, float y, float z, ITexture img, int layer,
			boolean quad) {
		super(x, y, layer, quad);
		// super(x, y, quad);
		this.z = z;
		// if (layer != 0)
		// setLayer(layer);
		this.image = img;
		// XXX:
		// privateCollisionList = new SingleCollisionList(this);
		if (image != null)
			setSize(image.getWidth(), image.getHeight());
		type.set("$_SPRITE");
	}

	public Sprite(Sprite obj) {
		super(obj);
		anglex = obj.anglex;
		angley = obj.angley;
		anglez = obj.anglez;
		autoReSizeDimensions = obj.autoReSizeDimensions;
		setRGBA(obj.colorRed, obj.colorGreen, obj.colorBlue, obj.colorAlpha);
		z = obj.z;
		isStatic = obj.isStatic;
		staticObj = obj.staticObj;
		cx = obj.cx;
		cy = obj.cy;
	}

	// -----------------------------------------------------------------
	// ---------------------DRAWING-------------------------------------
	// -----------------------------------------------------------------

	public void render() {
		// oldx = x;
		// oldy = y;
		// oldz = z;
		// -rallenta-
		// drawingloop();
		if (animo != null) {
			setImage(animo.get());// .getCurrentImage());
		}
		if (image == null)
			return;

		// not visible
		if (!visible)
			return;
		// not visible
		if (width <= 0 || height <= 0)
			return;
		// not visible
		if (colorAlpha <= 0)
			return;

		Camera camera = StaticRef.getCamera();
		float oldZoom = camera.getZoom2D();
		int nx = (int) (x - camera.x);
		int ny = (int) (y - camera.y);

		int incx = 0, incy = 0;// , incz = 0; // inutile ..
		if (anglex != 0 || angley != 0 || anglez != 0) {
			incx = width / 2;
			incy = height / 2;
		}

		if (fixedOnScreen
				|| ((nx < camera.getWidth() || ny < camera.getHeight()) && !((nx + width) < 0 || (ny + height) < 0))) {

			float translatex, translatey;
			// * GL11.glLoadIdentity();
			if (!fixedOnScreen) {
				// * GL11.glTranslatef(nx + incx, ny + incy, 0);
				translatex = nx + incx;
				translatey = ny + incy;
			} else {
				translatex = (float) x + incx;
				translatey = (float) y + incy;
				camera.zoom2D(1.0f);
			}

			OpenGLState.enableBlending();
			ITexture alphaMask = image.getAlphaMask();
			if (incx != 0) { // if must be roteated
				GL11.glTranslatef(nx + incx - cx, ny + incy - cy, 0);
				GL11.glRotatef(anglex, 1, 0, 0);
				GL11.glRotatef(angley, 0, 1, 0);
				GL11.glRotatef(anglez, 0, 0, 1);

				if (alphaMask != null && colorAlpha == 1) {
					GL11.glColor4f(1, 1, 1, 1);
					GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO);
					alphaMask.bind();
					drawPlainCenter(alphaMask);
					GL11.glColor4f(colorRed, colorGreen, colorBlue, colorAlpha);
					GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
					image.bind();
					drawPlainCenter(image);
				} else {
					if (colorAlpha != 1) {
						OpenGLState.enableBlending();
						GL11.glBlendFunc(GL11.GL_SRC_ALPHA,
								GL11.GL_ONE_MINUS_SRC_ALPHA);
					} else
						OpenGLState.disableBlending();
					GL11.glColor4f(colorRed, colorGreen, colorBlue, colorAlpha);
					image.bind();
					drawPlainCenter(image);
				}
				GL11.glLoadIdentity();
			} else { // not roteated
				if (alphaMask != null && colorAlpha == 1) {
					GL11.glColor4f(1, 1, 1, 1);
					GL11.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO);
					alphaMask.bind();
					drawPlain(translatex - cx, translatey - cy, alphaMask);
					GL11.glColor4f(colorRed, colorGreen, colorBlue, colorAlpha);
					GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
					image.bind();
					drawPlain(translatex - cx, translatey - cy, image);
				} else {
					if (colorAlpha != 1) {
						OpenGLState.enableBlending();
						GL11.glBlendFunc(GL11.GL_SRC_ALPHA,
								GL11.GL_ONE_MINUS_SRC_ALPHA);
					} else
						OpenGLState.disableBlending();
					GL11.glColor4f(colorRed, colorGreen, colorBlue, colorAlpha);
					image.bind();
					drawPlain(translatex - cx, translatey - cy, image);
				}
			}
			if (fixedOnScreen)
				camera.zoom2D(oldZoom);
		}
		camera.objectsAtScreen.add(this);
	}

	protected void drawPlainCenter(ITexture image) {
		GL11.glBegin(GL11.GL_QUADS); // Draw A Quad
		GL11.glNormal3f(0f, 0f, 3f);
		GL11.glTexCoord2f(image.getXStart(), image.getYStart());
		GL11.glVertex2f(-width / 2, -height / 2);
		GL11.glTexCoord2f(image.getXStart(), image.getYEnd());
		GL11.glVertex2f(-width / 2, +height / 2);
		GL11.glTexCoord2f(image.getXEnd(), image.getYEnd());
		GL11.glVertex2f(+width / 2, +height / 2);
		GL11.glTexCoord2f(image.getXEnd(), image.getYStart());
		GL11.glVertex2f(+width / 2, -height / 2);
		GL11.glEnd();
	}

	/** draw a dinamic plain */
	protected void drawPlain(float x, float y, ITexture image) {
		if (!isStatic) {
			GL11.glBegin(GL11.GL_QUADS); // Draw A Quad
			GL11.glTexCoord2f(image.getXStart(), image.getYStart());
			GL11.glVertex2f(x, y);
			GL11.glTexCoord2f(image.getXEnd(), image.getYStart());
			GL11.glVertex2f(x + width, y);
			GL11.glTexCoord2f(image.getXEnd(), image.getYEnd());
			GL11.glVertex2f(x + width, y + height);
			GL11.glTexCoord2f(image.getXStart(), image.getYEnd());
			GL11.glVertex2f(x, y + height);
			GL11.glEnd();
		} else if (staticObj != null)
			staticObj.render();
		else
			Utility.error("DrawPlain() mylist<=0 (or dinamic obj) "
					+ "in \"Sprite\"", "Sprite.drawPlain()");
	}

	// -----------------------------------------------------------------
	// ----------------------USER METHODS-------------------------------
	// -----------------------------------------------------------------

	/**
	 * sets the image of sprite
	 * 
	 * @param image
	 *            the image to sets
	 * @see #getImage()
	 */
	@Method("change image") public void setImage(@Info("image") ITexture image) {
		if (image != null) {
			if (this.autoReSizeDimensions) {
				int w = image.getWidth();
				int h = image.getHeight();
				if (this.image != null)
					if (width != w || height != h) {
						cx += (w - width) / 2;
						cy += (h - height) / 2;
					}
				width = w;
				height = h;
			} else if (this.image == null || width == 0 || height == 0) {
				width = image.getWidth();
				height = image.getHeight();
			}
		}
		this.image = image;
	}

	/**
	 * returns the current image of sprite.
	 * 
	 * @see #setImage( ITexture )
	 * @return current image
	 */
	public ITexture getImage() {
		return image;
	}

	/**
	 * sets the dimension of sprite
	 * 
	 * @param width
	 *            width of sprite
	 * @param height
	 *            height of sprite
	 * @see #getWidth()
	 * @see #getHeight()
	 */
	@Method("set the Dimension")//
	public void setSize(@Width @Info("width") int width,
			@Height @Info("height") int height) {
		if (isStatic) {
			Utility.error("setSize(int,int) in Sprite : "
					+ "can't set the size of a static image",
					"Sprite.setSize(int,int)");
			return;
		}
		super.setSize(width, height);
	}

	/**
	 * sets the saturation colors.<br>
	 * the values must be in the range of 0:1<br>
	 * Caution: there is not any check that the value that you have inserted is
	 * corrected<br>
	 * 
	 * @param red
	 *            red component
	 * @param green
	 *            green component
	 * @param blue
	 *            blue component
	 * @param alpha
	 *            alpha component
	 * @see #isUsingAlpha()
	 * @see #useAlpha(boolean)
	 */
	@Method("set Saturation (RGBA)")//
	public void setRGBA(@Info("Red") float red, @Info("Green") float green,
			@Info("Blue") float blue, @Info("Alpha") float alpha) {
		colorRed = Math.max(Math.min(red, 1), 0);
		colorGreen = Math.max(Math.min(green, 1), 0);
		colorBlue = Math.max(Math.min(blue, 1), 0);
		colorAlpha = Math.max(Math.min(alpha, 1), 0);
	}

	/**
	 * sets if use the alpha channel or not<br>
	 * if you set to use the alphachannel, if the colorAlpha field is equal to
	 * 1.0f it will be changed as 1.1f<br>
	 * if you set to don't use the alphachannel, if the colorAlpha field is
	 * different from 1.0f it will be changed as 1.0f<br>
	 * I advise you to look the sources to understand this..
	 * 
	 * @param value
	 *            indicates if use the alpha channel or not
	 * @see #isUsingAlpha()
	 * @see #setRGBA(float, float, float, float)
	 */
	public void useAlpha(boolean value) {
		if (value) {
			if (colorAlpha == 1.0f) {
				colorAlpha = 0.99f;
			}
		} else {
			if (colorAlpha != 1.0f) {
				colorAlpha = 1.0f;
			}
		}
	}

	/**
	 * returns if the sprite is using the alpha channel or not
	 * 
	 * @return if the sprite is using the alpha channel or not
	 * @see #useAlpha(boolean)
	 * @see #setRGBA(float, float, float, float)
	 */
	public boolean isUsingAlpha() {
		return colorAlpha != 1.0f;
	}

	// -----------------------------------------------------------------
	// ------------------------- STATICS -------------------------------
	// -----------------------------------------------------------------

	/**
	 * sets to use the static image: <br>
	 * a static image can't change the size (width and height)
	 * 
	 * @see #setStatic(StaticObject)
	 * @see #isStatic()
	 */
	public void setStatic(boolean value) {
		if (value) { // static
			if (isStatic) {
				Utility.error("OPTIMIZATION Object already static : "
						+ "setStatic( bool ) in Sprite",
						"Sprite.setStatic(bool)#!dinamic");
			} else
				isStatic = true;
		} else { // dinamic
			if (!isStatic) {
				Utility.error("OPTIMIZATION Object already dinamic : "
						+ "setStatic( bool ) in Sprite",
						"Sprite.setStatic(bool)#dinamic");
			} else
				isStatic = false;
		}
	}

	/**
	 * link a static image to the Sprite
	 * 
	 * @see #setStatic( boolean )
	 * @see #isStatic()
	 */
	public void setStatic(StaticObject obj) {
		staticObj = obj;
		if (obj == null) {
			isStatic = false;
		} else {
			obj.add(this);
			isStatic = true;
		}
	}

	/**
	 * returns if the obj is static or dinamic
	 * 
	 * @see #setStatic( boolean )
	 * @see #setStatic( StaticObject )
	 */
	public boolean isStatic() {
		return isStatic;
	}

	// -----------------------------------------------------------------
	// ----------------------- DESTROY -------------------------------
	// -----------------------------------------------------------------

	public void destroy() {
		if (isDestroyed())
			return;
		// remove itself from the sprite list of GE
		super.destroy();
		if (isStatic)
			if (staticObj != null)
				staticObj.remove(this);
			else
				Utility.error("destroy() in Sprite: static "
						+ "sprite whitout static Image", "Sprite.destroy()");
	}

	// public boolean isDestroyed() {
	// return destroyed;
	// }
	//
	// public void onDestroy() {
	// }

	// -----------------------------------------------------------------
	// ---------------------------- PLAIN ------------------------------
	// -----------------------------------------------------------------
	@Override/**
				 * returns the x coordinate relative to WORLD<br>
				 * note: the cx influence the result of this method.
				 * 
				 * @return x - cx
				 */
	public float getX() {
		return super.getX() - cx;
	}

	@Override/**
				 * returns the y coordinate relative to WORLD<br>
				 * note: the cy influence the result of this method.
				 * 
				 * @return y - cy
				 */
	public float getY() {
		return super.getY() - cy;
	}

	/**
	 * returns the x coordinate relative to WORLD<br>
	 * note: the cx NOT influence the result of this method.
	 * 
	 * @return x
	 */
	public float getXIndipendent() {
		return super.getX();
	}

	/**
	 * returns the y coordinate relative to WORLD<br>
	 * note: the cy NOT influence the result of this method.
	 * 
	 * @return y
	 */

	public float getYIndipendent() {
		return super.getY();
	}

	/**
	 * returns the x coordinate relative to WORLD<br>
	 * note: the cx NOT influence the result of this method.
	 * 
	 * @return x
	 */
	public float getXIndipendentOnScreen() {
		return super.getX();
	}

	/**
	 * returns the y coordinate relative to WORLD<br>
	 * note: the cy NOT influence the result of this method.
	 * 
	 * @return y
	 */

	public float getYIndipendentOnScreen() {
		return super.getY();
	}

	/**
	 * returns the rotation of the object<br>
	 * the rotation is in degree
	 * 
	 * @return the rotation angle in degree
	 */
	public float getAnglez() {
		return anglez;
	}

	/**
	 * sets the rotation of the object<br>
	 * the rotation is in degree
	 * 
	 * @param anglez
	 *            the rotation angle in degree
	 */
	@Method("Rotate object")//
	public void setAnglez(@Angle @Info("rotation in degree") float anglez) {
		this.anglez = anglez;
	}

	public Object clone() {
		return new Sprite(this);
	}

}
